--[[
关于CJK扩展字符
  CJK = 中日韩（China, Japan, Korea），这个主要是指的东亚地区使用汉字及部分衍生偏僻字的字符集
  （由于其使用频率非常低，一般的电脑系统里没有相关的字符，因此不能显示这些字）

查询unicode 编码
  1. https://unicode.org/charts/

导出函数
  1. charset_filter: 滤除含 CJK 扩展汉字的候选项
  2. charset_comment_filter: 为候选项加上其所属字符集的注释
--]]

-- 定义字符集
local charsets = {
    ["CJK"] = { first = 0x4E00, last = 0x9FFF }, -- CJK Unified Ideographs - https://unicode.org/charts/PDF/U4E00.pdf
    ["ExtA"] = { first = 0x3400, last = 0x4DBF }, -- CJK Unified Ideographs Extension A - https://unicode.org/charts/PDF/U3400.pdf
    ["ExtB"] = { first = 0x20000, last = 0x2A6DF }, -- CJK Unified Ideographs Extension B - https://unicode.org/charts/PDF/U20000.pdf
    ["ExtC"] = { first = 0x2A700, last = 0x2B73F }, -- CJK Unified Ideographs Extension C - https://unicode.org/charts/PDF/U2A700.pdf
    ["ExtD"] = { first = 0x2B740, last = 0x2B81F }, -- CJK Unified Ideographs Extension D - https://unicode.org/charts/PDF/U2B740.pdf
    ["ExtE"] = { first = 0x2B820, last = 0x2CEAF }, -- CJK Unified Ideographs Extension E - https://unicode.org/charts/PDF/U2B820.pdf
    ["ExtF"] = { first = 0x2CEB0, last = 0x2EBEF }, -- CJK Unified Ideographs Extension F - https://unicode.org/charts/PDF/U2CEB0.pdf
    ["ExtG"] = { first = 0x30000, last = 0x3134A }, -- CJK Unified Ideographs Extension G - https://unicode.org/charts/PDF/U30000.pdf
    ["Compat"] = { first = 0x2F800, last = 0x2FA1F } -- CJK Compatibility Ideographs Supplement - https://unicode.org/charts/PDF/U2F800.pdf
}

function char_to_codepoint(c)
    return utf8.codepoint(c, 1, 1)
end

function codepoint_to_charset(codepoint)
    return utf8.char(codepoint)
end

function is_utf8_char(c)
    if utf8.len(c) == 1 and utf8.codepoint(c) then
        return true
    end
end

-- 判断char是否在指定的charset中, 返回bool
local function is_char_in_charset(charset_name, c)
    local codepoint = char_to_codepoint(c)
    return codepoint >= charsets[charset_name].first and codepoint <= charsets[charset_name].last
end


-- 判断char是否为cjk-ext字符
--[[local function is_cjk_ext(c)
   return is_char_in_charset("ExtA", c) or is_char_in_charset("ExtB", c) or
      is_char_in_charset("ExtC", c) or is_char_in_charset("ExtD", c) or
      is_char_in_charset("ExtE", c) or is_char_in_charset("ExtF", c) or
      is_char_in_charset("Compat", c)
end]]

local function is_cjk_ext(c)
    for charset_name in pairs(charsets) do
        if charset_name ~= "CJK" and is_char_in_charset(charset_name, c) then
            return true
        end
    end
    --return false
end


-- 判断一个字符串是否包含CJK-扩展字符
local function is_text_contains_cjk_ext(text)
    for byte_index, codepoint in utf8.codes(text) do
        -- 得char_index
        --local codepoint = utf8.codepoint(text, byte_index)
        local c = utf8.char(codepoint)
        if (is_cjk_ext(c)) then
            -- 任意一个字符是cjk-ext, 则text包含cjk-ext
            return true
        end
    end
    --return false
end

-- charset_filter 将滤除含 CJK 扩展汉字的候选项：
local function charset_filter(input, env)
    for cand in input:iter() do
        -- 如果当前候选项 `cand` 不含 CJK 扩展汉字,
        if not is_text_contains_cjk_ext(cand.text) then
            yield(cand)
        end
        -- 上述条件不满足时，当前的候选 `cand` 没有被 yield。 因此过滤结果中将不含有该候选。
    end
end


-- charset_comment_filter 为单字候选项加上其所属字符集的注释
local function charset_comment_filter(input, env)
    for cand in input:iter() do
        if is_utf8_char(cand.text) then
            -- 判断当前候选内容 `cand.text` 中文字属哪个字符集
            for charset_name in pairs(charsets) do
                --[[ 修改候选的注释 `cand.comment`
                         因复杂类型候选项的注释不能被直接修改，
                         因此使用 `get_genuine()` 得到其对应真实的候选项
                    --]]
                if is_char_in_charset(charset_name, cand.text) then
                    cand:get_genuine().comment = cand.comment .. " " .. charset_name
                    break
                end
            end
        end
        -- 在结果中对应产生一个原始的带注释的候选
        yield(cand)
    end
end

-- 除去CJK
local function charset_comment_filter_except_cjk(input, env)
    for cand in input:iter() do
        if is_utf8_char(cand.text) then
            for charset_name in pairs(charsets) do
                if charset_name ~= "CJK" and is_char_in_charset(charset_name, cand.text) then
                    cand:get_genuine().comment = cand.comment .. " " .. charset_name
                    break
                end
            end
        end
        yield(cand)
    end
end

-- 本例中定义了两个 filter，故使用一个表将两者导出
return { filter = charset_filter,
         comment_filter = charset_comment_filter_except_cjk }
